package com.yeskery.nut.aop.handler;

import com.yeskery.nut.annotation.transaction.Transactional;
import com.yeskery.nut.aop.Execution;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.transaction.TransactionManager;

import java.lang.reflect.Method;

/**
 * Transaction注解的方法处理器
 * @author sprout
 * @version 1.0
 * 2022-08-28 12:49
 */
public class TransactionProxyMethodHandler extends BaseApplicationSupportProxyMethodHandler {

    /** 事务管理器对象 */
    private volatile TransactionManager transactionManager;

    /**
     * 构建Transaction注解的方法处理器
     * @param applicationContext 应用上下文
     */
    public TransactionProxyMethodHandler(ApplicationContext applicationContext) {
        super(applicationContext);
    }

    @Override
    public boolean support(Method method) {
        return method.isAnnotationPresent(Transactional.class);
    }

    @Override
    public void before(Method method, Execution execution, Object target) throws Exception {
        Transactional transactional = method.getAnnotation(Transactional.class);
        TransactionManager transactionManager = getTransactionManager();
        transactionManager.startTransaction(transactional.isolation(), transactional.propagation());
    }

    @Override
    public void after(Method method, Execution execution, Object target) throws Exception {
        getTransactionManager().commitTransaction();
    }

    @Override
    public void throwing(Method method, Execution execution, Object target, Throwable throwable) throws Exception {
        Transactional transactional = method.getAnnotation(Transactional.class);
        boolean rollback = false;
        for (Class<? extends Exception> exceptionClass : transactional.rollbackFor()) {
            if (exceptionClass.isAssignableFrom(throwable.getClass())) {
                rollback = true;
                break;
            }
        }
        if (rollback) {
            getTransactionManager().rollbackTransaction();
        } else {
            getTransactionManager().commitTransaction();
        }
    }

    /**
     * 获取事务管理器对象
     * @return 事务管理器对象
     */
    private TransactionManager getTransactionManager() {
        if (transactionManager == null) {
            synchronized (this) {
                if (transactionManager == null) {
                    transactionManager = getApplicationContext().getBean(TransactionManager.class);
                }
            }
        }
        return transactionManager;
    }
}
